<?php
declare (strict_types = 1);

namespace command\model;

use think\console\Command;
use think\console\Input;
use think\console\input\Argument;
use think\console\input\Option;
use think\console\Output;
use think\facade\Config;

class ModelCreate extends Command
{

    protected function configure()
    {
        // 指令配置
        $this->setName('model:create')
            ->addArgument('module', Argument::OPTIONAL, "app module name")
            ->addOption('tables', null, Option::VALUE_REQUIRED, 'op tables list')
            ->setDescription('auto create model');        
    }

    protected function execute(Input $input, Output $output)
    {
        $module = $input->getArgument('module');
        $modulePath = $module?$module."/":'';

        $db = $this->app->db;

        if ($input->hasOption('tables')) {
            $tables = $input->getOption('tables');
            $list = explode(',',$tables);
        } else {
        	$list = $db->getTables();
        }

        $prefix = Config::get('database.connections.mysql.prefix')??'';

        $path = $this->app->getBasePath().$modulePath."model";

        if (!is_dir($path)) {
            mkdir($path, 0755, true);
        }
        $stub = file_get_contents(__DIR__ . DIRECTORY_SEPARATOR . 'stubs' . DIRECTORY_SEPARATOR . 'model.stub');

        //获取项目配置，根据项目配置写入关联方法
        $projectFile = $this->app->getBasePath().DIRECTORY_SEPARATOR.'Project.php';
        if(is_file($projectFile)){
            $projectConfig = include_once $projectFile;
            $modelConfig = $module?($projectConfig[$module]['model']??[]):($projectConfig['model']??[]);
        }else{
            $modelConfig = [];
        }

        $model = config('ykcommand.auto.'.($module?$module.'.model':'model'));

        foreach ($list as $key => $value) {
            
            $name = str_replace("_","",ucwords(str_replace($prefix,'',$value),"_"));

            if(!empty($model)&&!in_array($name,$model))continue;

            $fields = $db->getFields($value);
            
            $fieldInfo = $this->parseField($fields);

            $namespace = 'app\model';

            if($module)$namespace = 'app\\'.$module.'\model';

            $pathName = $path . DIRECTORY_SEPARATOR . $name .".php";

            if(is_file($pathName))continue;//文件已存在跳过

            $relation = $this->buildRelation($modelConfig,$name);

            file_put_contents(
                $pathName,
                str_replace(
                    ['{$namespace}','{$name}','{$schema}','{$pk}','{$relation}'],
                    [$namespace,$name,$fieldInfo['schema'],"'".$fieldInfo['pk']."'",$relation],
                    $stub
                )
            );

        }

    	// 指令输出
    	$output->writeln('model');
    }

    /**
     * 格式化数据表字段
     *
     * @param array $fieldArr
     * @return void
     */
    private function parseField($fieldArr)
    {
        $schema = '['.PHP_EOL;
        $pk = "";
        foreach ($fieldArr as $key => $value) {
            $schema.='        "'.$value['name'].'"=>"'.$value['type'].'",'.PHP_EOL;
            if($value['primary']&&!$pk){
                $pk = $value['name'];
            }
        }

        $schema = trim($schema,',')."    ]";

        return ['pk'=>$pk,'schema'=>$schema];
    }

    /**
     * 构建关联关系方法
     *
     * @param array $modelConfig
     * @param string $modelName
     * @return void
     */
    private function buildRelation($modelConfig,$modelName)
    {
        $relations = $modelConfig[$modelName]??'';

        if(empty($relations))return '';

        $functions = [];
        foreach ($relations as $name=>$relation) {
            if(empty($relation['type']))continue;
            $tplName = empty($relation['bind'])?$relation['type']:$relation['type'].'Bind';
            $tplFile = __DIR__ . DIRECTORY_SEPARATOR . 'stubs' . DIRECTORY_SEPARATOR . 'relation' . DIRECTORY_SEPARATOR . $tplName . '.stub';
            if(is_file($tplFile)){
                $tplstr = file_get_contents($tplFile);
                $functions[]=str_replace(
                    ['{$comment}','{$relationName}','{$model}','{$foreignKey}','{$localKey}','{$joinType}','{$bind}'],
                    [$relation['comment'],$name,$relation['model'],$relation['foreignKey'],$relation['localKey'],$relation['joinType']??'INNER',$relation['bind']??''],
                    $tplstr
                );
            }
        }

        return implode(PHP_EOL.PHP_EOL,$functions);

    }
}
